#pragma once

#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/mod_devicetable.h>
#include <linux/spinlock.h>

#include <asm/byteorder.h>

typedef u32 phandle;
typedef u32 ihandle;

struct property {
	char	*name;
	int	length;
	void	*value;
	struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
	unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
	unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
	// struct bin_attribute attr;
#endif
};

struct device_node {
	const char *name;
	phandle phandle;
	const char *full_name;
	// struct fwnode_handle fwnode;

	struct	property *properties;
	struct	property *deadprops;	/* removed properties */
	struct	device_node *parent;
	struct	device_node *child;
	struct	device_node *sibling;
#if defined(CONFIG_OF_KOBJ)
	// struct	kobject kobj;
#endif
	unsigned long _flags;
	void	*data;
#if defined(CONFIG_SPARC)
	unsigned int unique_id;
	struct of_irq_controller *irq_trans;
#endif
};

/* initialize a node */
// extern struct kobj_type of_node_ktype;
// extern const struct fwnode_operations of_fwnode_ops;
static inline void of_node_init(struct device_node *node)
{
// #if defined(CONFIG_OF_KOBJ)
// 	kobject_init(&node->kobj, &of_node_ktype);
// #endif
// 	node->fwnode.ops = &of_fwnode_ops;
}

#ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
#else /* CONFIG_OF_DYNAMIC */
/* Dummy ref counting routines - to be implemented later */
static inline struct device_node *of_node_get(struct device_node *node)
{
	return node;
}
static inline void of_node_put(struct device_node *node) { }
#endif /* !CONFIG_OF_DYNAMIC */

/* Pointer for first entry in chain of all nodes. */
extern struct device_node *of_root;

/*
 * struct device_node flag descriptions
 * (need to be visible even when !CONFIG_OF)
 */
#define OF_DYNAMIC		1 /* (and properties) allocated via kmalloc */
#define OF_DETACHED		2 /* detached from the device tree */
#define OF_POPULATED		3 /* device already created */
#define OF_POPULATED_BUS	4 /* platform bus created for children */
#define OF_OVERLAY		5 /* allocated for an overlay */
#define OF_OVERLAY_FREE_CSET	6 /* in overlay cset being freed */

#ifdef CONFIG_OF

static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
{
	set_bit(flag, &n->_flags);
}

/*
 * OF address retrieval & translation
 */

/* Helper to read a big number; size is in cells (not bytes) */
static inline u64 of_read_number(const __be32 *cell, int size)
{
	u64 r = 0;
	while (size--)
		r = (r << 32) | be32_to_cpu(*(cell++));
	return r;
}

extern struct device_node *of_find_node_opts_by_path(const char *path,
	const char **opts);
static inline struct device_node *of_find_node_by_path(const char *path)
{
	return of_find_node_opts_by_path(path, NULL);
}

extern struct property *of_find_property(const struct device_node *np,
					 const char *name,
					 int *lenp);

extern int of_property_read_string(const struct device_node *np,
				   const char *propname,
				   const char **out_string);
extern const void *of_get_property(const struct device_node *node,
				const char *name,
				int *lenp);

#define for_each_property_of_node(dn, pp) \
	for (pp = dn->properties; pp != NULL; pp = pp->next)

extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));

#endif /* CONFIG_OF */

/* Default string compare functions, Allow arch asm/prom.h to override */
#if !defined(of_compat_cmp)
#define of_compat_cmp(s1, s2, l)	strcasecmp((s1), (s2))
#define of_prop_cmp(s1, s2)		strcmp((s1), (s2))
#define of_node_cmp(s1, s2)		strcasecmp((s1), (s2))
#endif
